home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / internet / amitcp3.0b / src.lha / src / amitcp / api / amiga_generic.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-08  |  23.2 KB  |  1,013 lines

  1. RCS_ID_C="$Id: amiga_generic.c,v 3.6 1994/03/22 08:41:36 jraja Exp $";
  2. /*
  3.  * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
  4.  *                    Helsinki University of Technology, Finland.
  5.  *                    All rights reserved.
  6.  * 
  7.  * Created: Fri Feb 12 13:26:55 1993 too
  8.  * Last modified: Wed Feb  2 21:35:39 1994 ppessi
  9.  * 
  10.  * HISTORY
  11.  * $Log: amiga_generic.c,v $
  12.  * Revision 3.6  1994/03/22  08:41:36  jraja
  13.  * Added calls to the libPtr->fdCallback to the appropriate places.
  14.  *
  15.  * Revision 3.5  1994/02/03  04:10:55  ppessi
  16.  * Changed the interface IOCTL codes
  17.  *
  18.  * Revision 3.4  1994/01/20  02:10:36  jraja
  19.  * Added support for 0 domain for ObtainSocket() if id is unique.
  20.  *
  21.  * Revision 3.3  1994/01/12  07:35:25  jraja
  22.  * Moved dtable functions (getLastSockFd(), _SetDTableSize() and
  23.  * _getdtablesize()) to amiga_generic2.c.
  24.  *
  25.  * Revision 3.2  1994/01/07  15:40:29  too
  26.  * Bug fixes after revision 3.1. Now tested.
  27.  *
  28.  * Revision 3.1  1994/01/04  14:38:35  too
  29.  * Added static function getLastSock(). Revised Dup2Socket, CloseSocket,
  30.  * SetDTableSize, ObtainSocket and ReleaseSocket to utilize socket usage
  31.  * bitmask. Changed behaviour of Dup2Socket when fd1 == -1.
  32.  * Moved some functions to amiga_generic2.c
  33.  *
  34.  * Revision 1.61  1993/12/22  08:16:22  jraja
  35.  * Cleaned some types, added 'static' to local functions.
  36.  *
  37.  * Revision 1.60  1993/10/16  17:20:49  too
  38.  * Fixed copying bug in SetDTableSize
  39.  *
  40.  * Revision 1.59  1993/09/14  22:15:16  jraja
  41.  * Added zeroing of obits in WaitSelect() if new memory is allocated for it.
  42.  *
  43.  * Revision 1.58  1993/08/01  22:15:07  ppessi
  44.  * Changed CloseSocket() to use api/apicall.h protos.
  45.  *
  46.  * Revision 1.57  1993/07/13  21:58:59  ppessi
  47.  * Added internal prototypes; changed interface ioctl codes to 'I'
  48.  *
  49.  * Revision 1.56  1993/06/13  16:38:43  too
  50.  * Added range check for fd2 in Dup2Socket()
  51.  *
  52.  * Revision 1.55  1993/06/11  20:18:09  too
  53.  * Added Dup2Socket(). Chahanged ioctl to IoctlSocket()
  54.  * Made function countSockets() which is needed to determine if last reference
  55.  * to that socket is given away.
  56.  *
  57.  * Revision 1.54  1993/06/07  12:37:20  too
  58.  * Changed inet_ntoa, netdatabase functions and WaitSelect() use
  59.  * separate buffers for their dynamic buffers
  60.  *
  61.  */
  62.  
  63. #include <conf.h>
  64.  
  65. #include <sys/param.h>
  66. #include <sys/systm.h>
  67. #include <sys/socketvar.h>
  68. #include <sys/kernel.h>
  69. #include <sys/ioctl.h>
  70. #include <sys/protosw.h>
  71. #include <sys/malloc.h>
  72. #include <sys/synch.h>
  73.  
  74. #include <sys/time.h>
  75. #include <sys/errno.h>
  76.  
  77. #include <sys/socket.h>
  78. #include <net/route.h>
  79.  
  80. #include <kern/amiga_includes.h>
  81.  
  82. #include <api/amiga_api.h>
  83. #include <api/amiga_libcallentry.h>
  84. #include <api/allocdatabuffer.h>
  85.  
  86. #include <api/apicalls.h>
  87.  
  88. #include <net/if_protos.h>
  89.  
  90. #include <amitcp/socketbasetags.h>
  91.  
  92. #include <kern/uipc_domain_protos.h>
  93. #include <kern/uipc_socket_protos.h>
  94. #include <kern/uipc_socket2_protos.h>
  95.  
  96. /* Local protos */
  97. static int selscan(struct SocketBase *p, 
  98.            fd_set *in, fd_set *ou, fd_set *ex, fd_mask *obits,
  99.            int nfd, int *retval, int *selitemcount_p);
  100. void selenter(struct SocketBase * p, struct newselitem ** hdr);
  101. static void unselect(register struct newselbuf * sb);
  102. void selwakeup(struct newselitem **hdr);
  103. static int soo_select(struct socket *so, int which, struct SocketBase *p);
  104. static int countSockets(struct SocketBase * libPtr, struct socket * so);
  105.  
  106. /*
  107.  * itimerfix copied from bsdss/server/kern/kern_time.c. since fields
  108.  * in struct timeval in amiga are ULONGs, values less than zero need
  109.  * not be checked. the second check, timeval less than resolution of
  110.  * the clock is not needed in amiga...hmm, is removed also.
  111.  */
  112. static inline int itimerfix(struct timeval *tv)
  113. {
  114.     if (tv->tv_sec > 100000000 || tv->tv_usec >= 1000000)
  115.         return (EINVAL);
  116. /*    if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
  117.         tv->tv_usec = tick;
  118. */    return (0);
  119. }
  120.  
  121. /*
  122.  * ffs() copied directly from bsdss/server/kern/subr_xxx.c
  123.  */
  124. static inline int ffs(register long mask)
  125. {
  126.   register int bit;
  127.  
  128.   if (!mask)
  129.     return(0);
  130.   for (bit = 1;; ++bit) {
  131.     if (mask&0x01)
  132.       return(bit);
  133.     mask >>= 1;
  134.   }
  135.   /* NOT REACHED */
  136. }
  137.  
  138.  
  139. /*
  140.  * Ioctl system call
  141.  */
  142.  
  143. LONG SAVEDS RAF4(_IoctlSocket,
  144.          struct SocketBase *,    libPtr,    a6,
  145.          LONG,            fdes,    d0,
  146.          ULONG,        cmd,    d1,
  147.          caddr_t,        data,    a0)
  148. #if 0
  149. {
  150. #endif
  151.  
  152.   register int error;
  153.   register u_int size;
  154.   struct socket *so;
  155.  
  156.   /*
  157.    * Note: Syscall semaphore is essential here if two processes can access
  158.    * the same socket. (can it be changed to spl_? ?)
  159.    */
  160.   CHECK_TASK();
  161.   ObtainSyscallSemaphore(libPtr);
  162.   
  163.   if (error = getSock(libPtr, fdes, &so))
  164.     goto Return;
  165.  
  166.   /*
  167.    * Interpret high order word to get size of the user data area
  168.    */
  169.   size = IOCPARM_LEN(cmd);
  170.   if (size == 0 || size > IOCPARM_MAX) {
  171.     error = ENOTTY;
  172.     goto Return;
  173.   }
  174.   if (!(cmd & IOC_IN) && cmd & IOC_OUT)
  175.     /*
  176.      * Zero the buffer so the user always
  177.      * gets back something deterministic.
  178.      */
  179.     bzero(data, size);
  180.   
  181.   switch (cmd) {
  182.   case FIOCLEX:
  183.   case FIONCLEX:        /* should this return error ???? */
  184.     goto Return;
  185.  
  186.   case FIOSETOWN:
  187.   case SIOCSPGRP:
  188.     /*
  189.      * data is a struct Task **, find corresponding SocketBase * and set owner
  190.      */
  191.     so->so_pgid = FindSocketBase(*(struct Task **)data);
  192.     goto Return;
  193.     
  194.   case FIOGETOWN:
  195.   case SIOCGPGRP:
  196.     if (so->so_pgid)
  197.       *(struct Task **)data = so->so_pgid->thisTask;
  198.     else
  199.       *(struct Task **)data = NULL;
  200.     goto Return;
  201.  
  202.   case FIONBIO:
  203.     if (*(int *)data)
  204.       so->so_state |= SS_NBIO;
  205.     else
  206.       so->so_state &= ~SS_NBIO;
  207.     goto Return;
  208.     
  209.   case FIOASYNC:
  210.     if (*(int *)data) {
  211.       so->so_state |= SS_ASYNC;
  212.       so->so_rcv.sb_flags |= SB_ASYNC;
  213.       so->so_snd.sb_flags |= SB_ASYNC;
  214.     } else {
  215.       so->so_state &= ~SS_ASYNC;
  216.       so->so_rcv.sb_flags &= ~SB_ASYNC;
  217.       so->so_snd.sb_flags &= ~SB_ASYNC;
  218.     }
  219.     goto Return;
  220.     
  221.   case FIONREAD:
  222.     *(int *)data = so->so_rcv.sb_cc;
  223.     goto Return;
  224.     
  225.   case SIOCATMARK:
  226.     *(int *)data = (so->so_state&SS_RCVATMARK) != 0;
  227.     goto Return;
  228.   }
  229.  
  230.   /*
  231.    * Interface/routing/protocol specific ioctls:
  232.    * interface and routing ioctls should have a
  233.    * different entry since a socket's unnecessary -- not really,
  234.    * ifioctl needs the socket (?)
  235.    */
  236.   if ((IOCGROUP(cmd) & 0XDF) == 'I') {
  237.     error = (ifioctl(so, cmd, data));
  238.     goto Return;
  239.   }
  240.   if (IOCGROUP(cmd) == 'r') {
  241.     error = (rtioctl(cmd, data));
  242.     goto Return;
  243.   }
  244.   error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 
  245.       (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)0));
  246.  
  247.  Return:
  248.   ReleaseSyscallSemaphore(libPtr);
  249.   API_STD_RETURN(error, 0);
  250. }
  251.  
  252.  
  253. /*
  254.  *  Semaphore to prevent select buffers from simultaneous modifications
  255.  */
  256. struct SignalSemaphore select_semaphore = { 0 };
  257.  
  258. struct newselbuf {
  259.   int s_state;
  260. #define    SB_CLEAR    0        /* wait condition cleared */
  261. #define    SB_WILLWAIT    1        /* will wait if not cleared */
  262. #define    SB_WAITING    2        /* waiting - wake up */
  263.   int s_count;
  264.   struct newselitem {
  265.     struct    newselitem  *    si_next;    /* next selbuf in item chain */
  266.     struct    newselitem **    si_prev;    /* back pointer */
  267.     struct    newselbuf   *    si_selbuf;    /* 'thread' waiting */
  268.   } s_item[0]; /* selitems are allocated at select when right
  269.           number of descriptors are known */
  270. };
  271.  
  272. void select_init(void)
  273. {
  274.   InitSemaphore(&select_semaphore);
  275. }
  276.  
  277. /*
  278.  *  symbolic names FREAD and FWRITE aren'n needed anywhere else if only
  279.  *  socket descriptors are in use.
  280.  */
  281. #define FREAD    0x1
  282. #define FWRITE    0x2
  283.  
  284. /*
  285.  * Select(), selscan(), selenter(), selwakeup() and unselect() are taken from
  286.  * ../server/kern/sys_generic.h in bsdss distribution. soo_select() is
  287.  * taken from ../server/kern/sys_socket.h, same distribution.
  288.  */
  289.  
  290. /* 
  291.  * Althrough the fd_set is used as the type of the masks, the size
  292.  * of the fd_set is not fixed, and is indeed calculated from nfds.
  293.  */
  294. LONG SAVEDS RAF7(_WaitSelect,
  295.          struct SocketBase *,    libPtr,        a6,
  296.          ULONG,            nfds,        d0,
  297.          fd_set *,        readfds,    a0,
  298.          fd_set *,        writefds,    a1,
  299.          fd_set *,        exeptfds,    a2,
  300.          struct timeval *,    timeout,    a3,
  301.          ULONG *,        sigmp,        d1)
  302. #if 0
  303. {
  304. #endif
  305.   
  306.   fd_mask * obits;
  307.   u_int obitsize;  /* in bytes */
  308.   int error, retval;
  309.   int selitemcount;
  310.   ULONG sigmask = sigmp ? *sigmp : 0;
  311.  
  312.   struct newselbuf * newselbuf;
  313.   
  314.   CHECK_TASK();
  315.  
  316.   if (nfds > libPtr->dTableSize)
  317.     nfds = libPtr->dTableSize;    /* forgiving; slightly wrong */
  318.   
  319.   if (timeout && itimerfix(timeout)) {
  320.     error = EINVAL;
  321.     goto Return;
  322.   }
  323.   
  324.   /*
  325.    *    We use selscan twice each time around the loop.
  326.    *    The first time, we actually put ourself on device chains.
  327.    *    The second time, we make a "fast" check for a true condition.
  328.    *    selenter does nothing and we don't need to use unselect.
  329.    *    We only need to zero obits once because if selscan
  330.    *    turns on a bit it returns non-zero and we stop.
  331.    *
  332.    *    The "fast" scan is also done before the loop is ever entered.
  333.    *
  334.    *    We need to allocate some temporary buffers for output bit masks
  335.    *    and, later for selitems. The amount of selitems needed is
  336.    *    calculated during the first selscan -- when selenter does nothing
  337.    */
  338.  
  339.   obitsize = howmany(nfds, NFDBITS) * sizeof (fd_mask);
  340.   if (allocDataBuffer(&libPtr->selitems, 3 * obitsize) == FALSE) {
  341.     error = ENOMEM;
  342.     goto Return;
  343.   }
  344.   obits = (fd_mask *)libPtr->selitems.db_Addr;
  345.  
  346.   aligned_bzero((caddr_t)obits, 3 * obitsize);
  347.  
  348.   /*
  349.    *    We make a first pass to check for conditions
  350.    *    which are already true.  Clearing uu_sb
  351.    *    will keep selenter from doing anything.
  352.    */
  353.   libPtr->p_sb = 0;
  354.   error = selscan(libPtr, readfds, writefds, exeptfds,
  355.           obits, nfds, &retval, &selitemcount);
  356.  
  357.   /*
  358.    *    Check if the 'real' loop should be entered.
  359.    */
  360.   if (!error && !retval) {
  361.     if (timeout == NULL || timeout->tv_secs != 0L || timeout->tv_micro != 0L) {
  362.     
  363.       /*
  364.        * Send timeout if there is any.
  365.        */
  366.       if (timeout)
  367.     tsleep_send_timeout(libPtr, timeout);
  368.  
  369.       /*
  370.        * Now, make sure there is room for all the selitems...
  371.        */
  372.       if (allocDataBuffer(&libPtr->selitems,
  373.               3 * obitsize + sizeof (struct newselbuf) +
  374.               selitemcount * sizeof(struct newselitem)) == FALSE) {
  375.     error = ENOMEM;
  376.     goto Return;
  377.       }
  378.       /*
  379.        * We need to clear obits again _if_ the memory area for it has 
  380.        * changed.
  381.        */
  382.       if ((fd_mask *)libPtr->selitems.db_Addr != obits) {
  383.     obits = (fd_mask *)libPtr->selitems.db_Addr;
  384.     aligned_bzero((caddr_t)obits, 3 * obitsize);
  385.       }
  386.       newselbuf = (struct newselbuf *)((caddr_t)obits + (3 * obitsize));
  387.       
  388.       while (TRUE) {
  389.  
  390.     /*
  391.      *    Now we get serious about blocking.
  392.      *    selenter will put us on device chains.
  393.      *    We don't need select_lock here because
  394.      *    no other thread can get at selbuf yet.
  395.      */
  396.     
  397.     newselbuf->s_state = SB_WILLWAIT;
  398.     newselbuf->s_count = 0;
  399.     libPtr->p_sb = newselbuf;
  400.     
  401.     error = selscan(libPtr, readfds, writefds, exeptfds,
  402.             obits, nfds, &retval, &selitemcount);
  403.     if (error || retval) {
  404.       ObtainSemaphore(&select_semaphore);
  405.       unselect(newselbuf);
  406.       ReleaseSemaphore(&select_semaphore);
  407.       break;
  408.     }
  409.     
  410.     /*
  411.      *    If the state is already SB_CLEAR, then a selwakeup
  412.      *    slipped in after the selscan.
  413.      */
  414.     
  415.     ObtainSemaphore(&select_semaphore);
  416.     if (newselbuf->s_state == SB_CLEAR) {
  417.       unselect(newselbuf);
  418.       ReleaseSemaphore(&select_semaphore);
  419.     }
  420.     else {
  421.       newselbuf->s_state = SB_WAITING;
  422.       tsleep_enter(libPtr, (caddr_t)newselbuf, "select");
  423.       ReleaseSemaphore(&select_semaphore);
  424.       /* ReleaseSemaphore(&syscall_semaphore); don't have this */
  425.       
  426.       error = tsleep_main(libPtr, sigmask);
  427.       
  428.       /* ObtainSemaphore(&syscall_semaphore); see above */
  429.       ObtainSemaphore(&select_semaphore);
  430.       unselect(newselbuf);
  431.       ReleaseSemaphore(&select_semaphore);
  432.       
  433.       if (error != 0) {
  434.         /*
  435.          * The break at the end of this block means that selscan will NOT 
  436.          * be done after this. This provides faster response to the 
  437.          * used defined signals.
  438.          *
  439.          * Note also that the semantics of the tsleep_abort_timeout() has 
  440.          * changed; it is now accepted to call it even after the timeout
  441.          * has expired.
  442.          */
  443.         if (error == ERESTART || error == EWOULDBLOCK)
  444.           error = 0;
  445.         
  446.         break;        /* do not scan now */
  447.       }
  448.       
  449.     }
  450.     /*
  451.      *    Scan for true conditions. Clearing uu_sb
  452.      *    will keep selenter from doing anything.
  453.      */
  454.     libPtr->p_sb = 0;
  455.     error = selscan(libPtr, readfds, writefds, exeptfds,
  456.             obits, nfds, &retval, &selitemcount);
  457.     if (error || retval)
  458.       break;
  459.       } /* while (TRUE) */    
  460.  
  461.       if (timeout)        /* abort the timeout if any */
  462.     tsleep_abort_timeout(libPtr, timeout);
  463.     }
  464.   }
  465.  
  466.  Return:
  467.   libPtr->p_sb = 0;
  468.  
  469. #define    putbits(name, x) \
  470.   if (name) { \
  471.     aligned_bcopy(((caddr_t)obits) + (x * obitsize), \
  472.           (caddr_t)name, obitsize); \
  473.    }
  474.  
  475.   if (error == 0) {
  476.     if (sigmp)
  477.       *sigmp &= SetSignal(0L, sigmask);
  478.     
  479.     putbits(readfds, 0);
  480.     putbits(writefds, 1);
  481.     putbits(exeptfds, 2);
  482.   }
  483. #undef putbits
  484.  
  485.   API_STD_RETURN(error, retval);
  486. }
  487.  
  488. /* 
  489.  * Althrough the fd_set is used as the type of the masks, the size
  490.  * of the fd_set is not fixed, and is indeed calculated from nfd.
  491.  */
  492. static int 
  493. selscan(struct SocketBase *p,
  494.     fd_set * in,
  495.     fd_set * ou,
  496.     fd_set * ex,
  497.     fd_mask * obits,
  498.     int nfd,
  499.     int * retval,
  500.     int * selitemcount_p)
  501. {
  502.     register int which, i, j, selitemcount = 0;
  503.     register fd_mask bits;
  504.     register fd_set * cbits;
  505.     struct socket *so;
  506.     int flag;
  507.     int n = 0;
  508.     int error = 0;
  509.     u_int obitsize = howmany(nfd, NFDBITS); /* in longwords */
  510.  
  511.     for (which = 0; which < 3; which++) {
  512.         switch (which) {
  513.  
  514.         case 0:
  515.             flag = FREAD;
  516.             cbits = in;
  517.             break;
  518.         case 1:
  519.             flag = FWRITE;
  520.             cbits = ou;
  521.             break;
  522.         case 2:
  523.             flag = 0;
  524.             cbits = ex;
  525.             break;
  526.         }
  527.         if (cbits != NULL) {
  528.           for (i = 0; i < nfd; i += NFDBITS) {
  529.             bits = cbits->fds_bits[i/NFDBITS];
  530.             while ((j = ffs(bits)) && i + --j < nfd) {
  531.                 bits &= ~(1 << j);
  532.                 so = p->dTable[i + j];
  533.                 if (so == NULL) {
  534.                   error = EBADF;
  535.                   break;
  536.                 }
  537.                 selitemcount++;
  538.                 if (soo_select(so, flag, p)) {
  539.                   FD_SET(i + j, (fd_set *)
  540.                      (obits + (which * obitsize)));
  541.                   n++;
  542.                 }
  543.             }
  544.           }
  545.         }
  546.     }
  547.     *retval = n;
  548.     *selitemcount_p = selitemcount;
  549.     return (error);
  550. }
  551.  
  552. /*
  553.  * Add a select event to the current select buffer.
  554.  * Chain all select buffers that are waiting for
  555.  * the same event.
  556.  */
  557. void selenter(struct SocketBase *    p,
  558.           struct newselitem **    hdr)
  559. {
  560.     register struct newselbuf *sb = p->p_sb;
  561.  
  562.     if (sb) {
  563.         register struct newselitem **sip = hdr;
  564.         register struct newselitem *si;
  565.  
  566.         ObtainSemaphore(&select_semaphore);
  567.  
  568.         /* initialize this select item */
  569.         si = &sb->s_item[sb->s_count++];
  570.         si->si_selbuf = sb;
  571.  
  572.         /* and add it to the device chain */
  573.         if (si->si_next = *sip)
  574.         si->si_next->si_prev = &si->si_next;
  575.         *(si->si_prev = sip) = si;
  576.  
  577.         ReleaseSemaphore(&select_semaphore);
  578.     }
  579. }
  580.  
  581. static void
  582. unselect(register struct newselbuf * sb)
  583. {
  584.     int i;
  585.  
  586.     /*
  587.      *    We unchain the select items.
  588.      *    This assumes select_lock is held.
  589.      */
  590.  
  591.     for (i = 0; i < sb->s_count; i++) {
  592.         register struct newselitem *si = &sb->s_item[i];
  593.  
  594.         /*
  595.          *    We remove this item from its device chain.
  596.          *    If selwakeup already got to it, then this is a nop.
  597.          */
  598.  
  599.         *si->si_prev = si->si_next;
  600.     }
  601. }
  602.  
  603. /*
  604.  * Wakeup all threads waiting on the same select event.
  605.  * Do not clear the other select events that each thread
  606.  * is waiting on; thread will do that itself.
  607.  */
  608. void selwakeup(struct newselitem **hdr)
  609. {
  610.     register struct newselitem **sip;
  611.     register struct newselitem *si;
  612.  
  613.     ObtainSemaphore(&select_semaphore);
  614.  
  615.     for (sip = hdr; (si = *sip) != 0; sip = &si->si_next) {
  616.         register struct newselbuf *sb;
  617.         int old_state;
  618.  
  619.         /* for when unselect tries to dequeue this item */
  620.         si->si_prev = &si->si_next;
  621.  
  622.         /* check for wakeup */
  623.         sb = si->si_selbuf;
  624.         old_state = sb->s_state;
  625.         sb->s_state = SB_CLEAR;
  626.         if (old_state == SB_WAITING)
  627.         wakeup((caddr_t)sb);
  628.     }
  629.  
  630.     /* clear the device chain */
  631.     *(struct newselitem **)hdr = 0;
  632.     ReleaseSemaphore(&select_semaphore);
  633. }
  634.  
  635. static int
  636. soo_select(struct socket *so,
  637.            int which,
  638.            struct SocketBase *p)
  639. {
  640.     register spl_t s = splnet();
  641.  
  642.     switch (which) {
  643.  
  644.     case FREAD:
  645.         if (soreadable(so)) {
  646.             splx(s);
  647.             return (1);
  648.         }
  649.         sbselqueue(&so->so_rcv, p);
  650.         break;
  651.  
  652.     case FWRITE:
  653.         if (sowriteable(so)) {
  654.             splx(s);
  655.             return (1);
  656.         }
  657.         sbselqueue(&so->so_snd, p);
  658.         break;
  659.  
  660.     case 0:
  661.         if (so->so_oobmark ||
  662.             (so->so_state & SS_RCVATMARK)) {
  663.             splx(s);
  664.             return (1);
  665.         }
  666.         sbselqueue(&so->so_rcv, p);
  667.         break;
  668.     }
  669.     splx(s);
  670.     return (0);
  671. }
  672.  
  673. /*
  674.  * countSockets() counts how many references ONE task (SocketBase) have to a
  675.  * socket
  676.  */
  677.  
  678. static int
  679. countSockets(struct SocketBase * libPtr, struct socket * so)
  680. {
  681.   int i, count = 0;
  682.  
  683.   for (i = 0; i < libPtr->dTableSize; i++)
  684.     if (libPtr->dTable[i] == so)
  685.       count++;
  686.  
  687.   return count;
  688. }
  689.  
  690. LONG SAVEDS RAF2(_CloseSocket,
  691.          struct SocketBase *,    libPtr,    a6,
  692.          LONG,            fd,    d0)
  693. #if 0
  694. {
  695. #endif
  696.  
  697.   register int error;
  698.   struct socket *so;
  699.  
  700.   CHECK_TASK();
  701.   ObtainSyscallSemaphore(libPtr);
  702.  
  703.   /*
  704.    * Check from used sockets bitmask if this socket is in use
  705.    */
  706.   if (! FD_ISSET(fd, (fd_set *)(libPtr->dTable + libPtr->dTableSize))) {
  707.     error = EBADF;
  708.     goto Return;
  709.   }
  710.  
  711.   /*
  712.    * If the link library cannot free the fd, then we cannot do it either.
  713.    */
  714.   if (libPtr->fdCallback)
  715.     if (error = libPtr->fdCallback(fd, FDCB_FREE))
  716.       goto Return;
  717.  
  718.   FD_CLR(fd, (fd_set *)(libPtr->dTable + libPtr->dTableSize));
  719.  
  720.   if (error = getSock(libPtr, fd, &so)) {
  721. /*    error = ENOTSOCK;    /* well, bit set, but socket == NULL */
  722.     error = 0; /* ignore silently */
  723.     goto Return;
  724.   }
  725.   if (so->so_pgid == libPtr && countSockets(libPtr, so) == 1) 
  726.     so->so_pgid = NULL;        /* not ours any more */
  727.  
  728.   /*
  729.    * Decrease the reference count of a socket (AmiTCP addition) and return if
  730.    * not zero.
  731.    */
  732.   if (--so->so_refcnt <= 0)
  733.     error = soclose(so);
  734.  
  735.   /*
  736.    * now clear socket from descriptor table. Socket usage bitmask has been
  737.    * cleared earlier
  738.    */
  739.   libPtr->dTable[fd] = NULL;
  740.  
  741.  Return: 
  742.   ReleaseSyscallSemaphore(libPtr);
  743.   API_STD_RETURN(error, 0);
  744. }
  745.  
  746.  
  747. struct SocketNode {
  748.   struct MinNode    sn_Node;
  749.   LONG            sn_Id;
  750.   struct socket *    sn_Socket;
  751. };
  752.  
  753. /*
  754.  * checkId() checks that there are no released sockets w/ given id.
  755.  * used from function makeId().
  756.  */
  757.  
  758. static LONG checkId(int id)
  759. {
  760.   struct Node * sn;
  761.  
  762.   Forbid();
  763.   for (sn = releasedSocketList.lh_Head; sn->ln_Succ; sn = sn->ln_Succ)
  764.     if (((struct SocketNode *)sn)->sn_Id == id) {
  765.       Permit();
  766.       return EINVAL;
  767.     }
  768.   Permit();    
  769.   return 0;
  770. }
  771.  
  772. #define FIRSTUNIQUEID 65536
  773.  
  774. /*
  775.  * makeId() gets next unique id for socket to be released if *id is -1
  776.  * otherwise calls checkId for given *id.
  777.  * used from functions ReleaseSocket() and ReleaseCopyOfSocket().
  778.  */
  779. static LONG makeId(LONG id)
  780. {
  781.   static LONG uniqueId = FIRSTUNIQUEID;
  782.  
  783.   if (id == UNIQUE_ID) {
  784.     do {
  785.       uniqueId += sizeof (void *);
  786.       if (uniqueId < 0)
  787.     uniqueId = FIRSTUNIQUEID;
  788.     } while (checkId(uniqueId) != 0);
  789.  
  790.     return uniqueId;
  791.   }
  792.   else {
  793.     if (checkId(id) == 0)
  794.       return id;
  795.     else
  796.       return -1; /* error */
  797.   }
  798. }
  799.  
  800. LONG SAVEDS RAF3(_ReleaseSocket,
  801.          struct SocketBase *,    libPtr, a6,
  802.          LONG,            fd,    d0,
  803.          LONG,            id,    d1)
  804. #if 0         
  805. {
  806. #endif
  807.   struct SocketNode *sn;
  808.   struct socket *so;
  809.   int error = 0;
  810.  
  811.   CHECK_TASK();
  812.  
  813.   if ((ULONG)id >= FIRSTUNIQUEID && (id = makeId(id)) == -1) {
  814.     error = EINVAL;
  815.     goto Return;
  816.   }
  817.  
  818.   if ((error = getSock(libPtr, fd, &so)) != 0)
  819.     goto Return;
  820.  
  821.   if ((sn = AllocMem(sizeof (struct SocketNode), MEMF_PUBLIC)) == NULL) {
  822.     error = ENOMEM;
  823.     goto Return;
  824.   }
  825.   /*
  826.    * Tell the link library that the fd is free
  827.    */
  828.   if (libPtr->fdCallback)
  829.     if (error = libPtr->fdCallback(fd, FDCB_FREE)) {
  830.       FreeMem(sn, sizeof (struct SocketNode));
  831.       goto Return;
  832.     }
  833.   
  834.   if (so->so_pgid == libPtr && countSockets(libPtr, so) == 1) 
  835.     so->so_pgid = NULL;        /* not ours any more */
  836.   sn->sn_Id = id;
  837.   sn->sn_Socket = so;
  838.   libPtr->dTable[fd] = NULL;
  839.   FD_CLR(fd, (fd_set *)(libPtr->dTable + libPtr->dTableSize));
  840.   
  841.   Forbid();
  842.   AddTail(&releasedSocketList, (struct Node *)sn);
  843.   Permit();
  844.  
  845.  Return: API_STD_RETURN(error, id);
  846. }
  847.  
  848. LONG SAVEDS RAF3(_ReleaseCopyOfSocket,
  849.          struct SocketBase *,    libPtr, a6,
  850.          LONG,            fd,    d0,
  851.          LONG,            id,    d1)
  852. #if 0         
  853. {
  854. #endif
  855.   struct SocketNode *sn;
  856.   struct socket *so;
  857.   int error = 0;
  858.  
  859.   CHECK_TASK();
  860.  
  861.   if ((ULONG)id >= FIRSTUNIQUEID && (id = makeId(id)) == -1) {
  862.     error = EINVAL;
  863.     goto Return;
  864.   }
  865.  
  866.   if ((error = getSock(libPtr, fd, &so)) != 0)
  867.     goto Return;
  868.  
  869.   if ((sn = AllocMem(sizeof (struct SocketNode), MEMF_PUBLIC)) == NULL) {
  870.     error = ENOMEM;
  871.     goto Return;
  872.   }
  873.   /* so_pgid left intact */
  874.   sn->sn_Id = id;
  875.   sn->sn_Socket = so;
  876.   so->so_refcnt++;
  877.   Forbid();
  878.   AddTail(&releasedSocketList, (struct Node *)sn);
  879.   Permit();
  880.  
  881.  Return: API_STD_RETURN(error, id);
  882. }
  883.  
  884. LONG SAVEDS RAF5(_ObtainSocket,
  885.          struct SocketBase *,    libPtr,     a6,
  886.          LONG,            id,        d0,
  887.          LONG,            domain,        d1,
  888.          LONG,            type,        d2,
  889.          LONG,            protocol,    d3)
  890. #if 0
  891. {
  892. #endif
  893.  
  894.   struct protosw *prp;
  895.   struct Node * sn;
  896.   int error = 0;
  897.   LONG fd;
  898.  
  899.   CHECK_TASK();
  900.  
  901.   if (domain == 0) {
  902.     if (id < FIRSTUNIQUEID) {
  903.       error = EPFNOSUPPORT;
  904.       goto Return;
  905.     }
  906.   }
  907.   else {
  908.     if (protocol)
  909.       prp = pffindproto(domain, protocol, type);
  910.     else
  911.       prp = pffindtype(domain, type);
  912.     if (prp == 0)
  913.       error = EPROTONOSUPPORT;
  914.     if (prp->pr_type != type)
  915.       error = EPROTOTYPE;
  916.     if (error)
  917.       goto Return;
  918.   }  
  919.  
  920.   if ((error = sdFind(libPtr, &fd)) != 0)
  921.     goto Return;
  922.  
  923.   /*
  924.    * Tell the link library about the new fd
  925.    */
  926.   if (libPtr->fdCallback)
  927.     if (error = libPtr->fdCallback(fd, FDCB_ALLOC))
  928.       goto Return;
  929.   
  930.   Forbid();
  931.   for (sn = releasedSocketList.lh_Head; sn->ln_Succ; sn = sn->ln_Succ)
  932.     if (((struct SocketNode *)sn)->sn_Id == id) {
  933.       if (prp != ((struct SocketNode *)sn)->sn_Socket->so_proto)
  934.     continue;
  935.       Remove(sn);
  936.       Permit();
  937.       libPtr->dTable[fd] = ((struct SocketNode *)sn)->sn_Socket;
  938.       FD_SET(fd, (fd_set *)(libPtr->dTable + libPtr->dTableSize));
  939.       FreeMem(sn, sizeof (struct SocketNode));
  940.       goto Return;
  941.     }
  942.   /* here if sdFind succeeded but search of socket failed */
  943.   Permit();
  944.  
  945.   /*
  946.    * Free the just allocated fd
  947.    */
  948.   if (libPtr->fdCallback)
  949.     libPtr->fdCallback(fd, FDCB_FREE);
  950.  
  951.   error = EWOULDBLOCK;
  952.   
  953.  Return: API_STD_RETURN(error, fd);
  954. }
  955.  
  956. LONG SAVEDS RAF3(_Dup2Socket,
  957.          struct SocketBase *,    libPtr,     a6,
  958.          LONG,            fd1,        d0,
  959.          LONG,            fd2,        d1)
  960. #if 0     
  961. {
  962. #endif
  963.   LONG newfd;
  964.   int error = 0;
  965.   struct socket *so;
  966.  
  967.   CHECK_TASK();
  968.   ObtainSyscallSemaphore(libPtr); /*many tasks may have access to the socket */
  969.  
  970.   if (fd1 == -1)
  971.     so = NULL;
  972.   else if ((error = getSock(libPtr, fd1, &so)))
  973.     goto Return;
  974.  
  975.   if (fd2 == -1)
  976.     if ((error = sdFind(libPtr, &newfd)))
  977.       goto Return;
  978.     else
  979.       fd2 = newfd;
  980.   else {
  981.     if ((ULONG)fd2 >= libPtr->dTableSize) {
  982.       error = EBADF;
  983.       goto Return;
  984.     }
  985.     if (libPtr->dTable[fd2] != NULL)
  986.       CloseSocket(libPtr, fd2);
  987.     /*
  988.      * Check if the fd is free on the link library
  989.      */
  990.     if (libPtr->fdCallback)
  991.       if (error = libPtr->fdCallback(fd2, FDCB_CHECK))
  992.     goto Return;
  993.  
  994.   }
  995.   /*
  996.    * Tell the link library about the new fd
  997.    */
  998.   if (libPtr->fdCallback)
  999.     if (error = libPtr->fdCallback(fd2, FDCB_ALLOC))
  1000.       goto Return;
  1001.  
  1002.   FD_SET(fd2, (fd_set *)(libPtr->dTable + libPtr->dTableSize));
  1003.   
  1004.   if (so != NULL) {
  1005.     so->so_refcnt++;
  1006.     libPtr->dTable[fd2] = so;
  1007.   }
  1008.  
  1009.  Return:
  1010.   ReleaseSyscallSemaphore(libPtr);
  1011.   API_STD_RETURN(error, fd2);
  1012. }
  1013.